package com.ossjk.config.shiro;

import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.servlet.Filter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.ossjk.qlh.minapp.service.IMemberService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.alibaba.fastjson.JSON;
import com.ossjk.core.constant.Constant;
import com.ossjk.core.util.JwtTokenUtil;
import com.ossjk.core.vo.ResponseBean;

import org.springframework.data.redis.core.RedisTemplate;

/**
 * JwtFilter:jwt过滤器来作为shiro的过滤器
 *
 * @author zhangxiaoxiang
 * @date: 2019/07/12
 */
public class JwtFilter extends BasicHttpAuthenticationFilter implements Filter {

	public Logger log = LoggerFactory.getLogger(JwtFilter.class);
	private JwtTokenUtil jwtTokenUtil;
	private IMemberService iMemberService;
    private RedisTemplate<String, String> redisTemplate;


	public JwtFilter(JwtTokenUtil jwtTokenUtil, IMemberService iMemberService, RedisTemplate<String, String> redisTemplate) {
		this.jwtTokenUtil = jwtTokenUtil;
	    this.iMemberService=iMemberService;
	    this.redisTemplate=redisTemplate;
	}

	/**
	 * 执行登录
	 *
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@Override
	protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
		HttpServletRequest httpServletRequest = (HttpServletRequest) request;
		HttpServletResponse httpServletResponse = (HttpServletResponse) response;
		request.setCharacterEncoding("UTF-8");
		response.setCharacterEncoding("UTF-8");
		String token = jwtTokenUtil.getToken(httpServletRequest);
		ResponseBean responseBean = null;
		try {
			JwtToken jwtToken = new JwtToken(token);
			// 提交给realm进行登入，如果错误他会抛出异常并被捕获
			getSubject(request, response).login(jwtToken);
			// 如果没有抛出异常则代表登入成功，返回true
			return true;
		} catch (NoTokenException e) {
			// token失效
			responseBean = new ResponseBean(Constant.RESPONSE_CODE_NOLOGIN, Constant.RESPONSE_MSG_NOLOGIN);
		} catch (TokenFlushException e) {
			// token刷新
			String uid = jwtTokenUtil.getUserId(token);

			//分发token
			String tokenStr = jwtTokenUtil.generalToken(uid, iMemberService.getById(uid).getName());
			//设置token
			redisTemplate.boundValueOps(Constant.REQUEST_HEADER_TOKEN +uid).set(tokenStr,jwtTokenUtil.getDuration(), TimeUnit.MILLISECONDS);
			responseBean = new ResponseBean(Constant.RESPONSE_CODE_REFRESH, Constant.RESPONSE_MSG_REFRESH, tokenStr);
		} catch (AuthenticationException e) {
			// token失效
			responseBean = new ResponseBean(Constant.RESPONSE_CODE_BADTOKEN, Constant.RESPONSE_MSG_BADTOKEN);
		}
		String json = JSON.toJSONString(responseBean);
		log.warn("拦截请求：" + httpServletRequest.getRequestURI() + ",原因：" + json);
		response.setContentType("application/json");
		PrintWriter out = response.getWriter();
		out.print(json);
		out.flush();
		out.close();
		return false;

	}

	/**
	 * 执行登录认证
	 *
	 * @param request
	 * @param response
	 * @param mappedValue
	 * @return
	 */
	@Override
	protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
		try {
			return executeLogin(request, response);
			// return true;有一篇博客这里直接返回true是不正确的,在这里我特别指出一下
		} catch (Exception e) {
			log.error("拦截器报错", e);
			return false;
		}
	}

}
